
class_name SceneSelectManage
extends Node2D




enum SelectMangerMode {
	## 没有仍和含义，仅用来初始化
	NONE,
	## 显示移动， 仅显示
	SHOW_MOVE,
	## 显示攻击，仅显示
	SHOW_ATTACK,
	## 显示移动，可交互
	MOVE,
	## 显示攻击，可交互
	ATTACK,
	## 显示技能，可交互
	SKILL
}




## 层级模板
## 现在 select-manage 按照 layer 来管理
## 因为 select-manage 与技能的关联比较紧密，所以
## layer 有很多的回调参数，可以用来实现效果
var _layer_temp: Dictionary = {
	## 名字
	"name": "",
	## 模式
	"mode": SelectMangerMode.NONE,
	## 点击时的回调方法
	## * 这个回调方法需要接受一个字典
	## * 这个回调的参数为层级的 callable_arg 属性
	"callable": func (_arg: Dictionary) -> void: pass,
	## 回调参数
	"callable_arg": {},
	## 区域
	"areas": [],
	## 清除的回调
	## 如果有的话，会调用这个回调
	## * 这个回调应该接受一个字典类型的参数，层级字典将作为参数
	## * 这个回调应该返回一个布尔值，为 true 时将会执行默认的清除操作，否则不会做多余的事
	"clear_callable": func (_arg: Dictionary) -> bool: return true,
	## 移动的回调
	## 如果有的话，会调用这个回调
	## * 这个回调应该接受一个字典类型的参数，层级字典与一些额外信息将作为参数
	## * 这个回调需要一个返回值，返回一个 bool 值：
	## - 如果返回 true 就会阻止后续层级的move响应
	## - 如果返回 false 就会继续后续层级的move响应
	"move_callable": func (_arg: Dictionary) -> bool: return false,
	## 是否回应移动
	## 如果为 true 就会接受，默认不接受
	"is_accept_move": false
}
var layer: Array[Dictionary] = []
## 是否在等待选取
## 如果为 true 就会拦截输入信号
var await_handle: bool = false
## 如果需要的话
## 可以设置等待选取处理的层级
## TODO
var await_handle_layer: int = -1




## 构造一个区域
func create_area() -> Sprite2D:
	var sp: Sprite2D = Sprite2D.new()
	add_child(sp)
	sp.texture = load("res://assets/images/select.png")
	return sp




## 显示范围
## _positions: 要显示的一系列坐标
## _mode: 显示模式
## _callable: 点击的回调方法
## _callable_arg: 点击的回调方法的参数
## _name: 层级的名字，如果无所谓就不用设置,如果不设置的话会设置名字为下标数字
## *该方法现在会返回一个数组，第一个是 <层级所在下表> 第二个是 <层级名字>
func show_range(
	_positions: PackedVector2Array, 
	_mode: SelectMangerMode, 
	_callable: Callable = func (_arg: Dictionary) -> void: pass, 
	_callable_arg: Dictionary = {},
	_name: String = "") -> Array:
	
	show()
	
	var areas: Array[Sprite2D] = []
	for item in _positions:
		var sp := create_area()
		sp.position = item
		# 设置区域颜色
		area_set_mode_match_color(sp, _mode)
		areas.append(sp)
	
	# 创建 layer
	var n: String = ""
	if _name.is_empty():
		n = str(layer.size())
	
	var lt = _layer_temp.duplicate(true)
	lt["name"] = n
	lt["mode"] = _mode
	lt["callable"] = _callable
	lt["callable_arg"] = _callable_arg
	lt["areas"] = areas
	
	layer.append(lt)
	await_handle = true
	
	#print("layer > ", JSON.stringify(layer, "\t"))
	
	return [layer.size() - 1, n]




func set_layer_clear_callable(_layer: int, _callable: Callable) -> void:
	var l = get_layer_index(_layer)
	l["clear_callable"] = _callable
	pass




func is_show(_layer: Dictionary) -> bool:
	if _layer["mode"] == SelectMangerMode.SHOW_ATTACK or \
		_layer["mode"] == SelectMangerMode.SHOW_MOVE:
		return true
	return false




## 点击调用的方法
func pointer_callable(_pointer: ScenePointer) -> void:
	# 判断是否点击到显示图块上
	var res: Array = get_position_top_area(_pointer.position)
	#print("res > ", JSON.stringify(res, "\t"))
	
	# 如果不在图块上
	# 就要消除一层
	if res.is_empty():
		if layer.size() > 0:
			await_handle = false
			remove_layer_int(layer.size() - 1)
		return
	
	var lay: Dictionary = get_layer_index(res[0])
	#print("lay > ", JSON.stringify(lay, "\t"))
	
	# 如果为空就返回
	if lay.is_empty():
		return
	
	var lay_mode = lay["mode"]
	var lay_ca = lay["callable_arg"]
	var lay_c = lay["callable"]
	
	# 添加一个位置
	lay_ca["target_position"] = _pointer.position
	
	# 如果没有点击到图块上，且现在是 move 或 attack 就清除
	if lay_mode == SelectMangerMode.MOVE or lay_mode == SelectMangerMode.ATTACK:
		if lay_c.call(lay_ca):
			await_handle = false
			remove_layer_int(res[0])
		return
	# 如果只是展示直接清除掉
	elif lay_mode == SelectMangerMode.SHOW_MOVE or lay_mode == SelectMangerMode.SHOW_ATTACK:
		await_handle = false
		remove_layer_int(res[0])
	# 如果是效果就调用回调
	elif lay_mode == SelectMangerMode.SKILL:
		if lay_c.call(lay_ca):
			await_handle = false # 解除阻塞
			remove_layer_int(res[0]) # 删除该层
		return
	
	# 调用回调并传入参数,
	# 如果回调结果返回 true 就清除显示并重置状态
	# 否则继续等待回调
	if lay_c.call(lay_ca):
		await_handle = false
		remove_layer_int(res[0])




## 删除 layer
## 需要传入层级的名字 string
## 第二个参数为真则会检查清除回调，否则无视
func remove_layer_name(_name: String, _call: bool = true) -> void:
	for i in layer:
		if i["name"] == _name:
			# 调用清除的回调
			if _call:
				var res : bool = i["clear_callable"].call(i)
				if res:
					for a in i["areas"]:
						if is_instance_valid(a):
							a.queue_free()
					layer.erase(i)
			else:
				for a in i["areas"]:
					if is_instance_valid(a):
						a.queue_free()
				layer.erase(i)
			return




## 删除 layer
## 需要传入层级的索引 int
## 第二个参数为真则会检查清除回调，否则无视
func remove_layer_int(_index: int, _call: bool = true) -> void:
	if _index >= layer.size():
		return
	#print("remove layer int > ", layer)
	# 调用清除的回调
	var lay: Dictionary = layer[_index]
	if _call:
		var res : bool = lay["clear_callable"].call(lay)
		if res:
			for a in lay["areas"]:
				if is_instance_valid(a):
					a.queue_free()
			layer.remove_at(_index)
	else:
		for a in lay["areas"]:
			if is_instance_valid(a):
				a.queue_free()
		layer.remove_at(_index)




## 获取 layer
## 根据名字来搜索
func get_layer_name(_name: String) -> Dictionary:
	for i in layer:
		if i["name"] == _name:
			return i
	return {}




## 获取 layer
## 根据下标来获取
func get_layer_index(_index: int) -> Dictionary:
	if _index < layer.size():
		return layer[_index]
	return {}




## 设置与mode匹配的颜色
func area_set_mode_match_color(_area: Sprite2D, _mode: SelectMangerMode) -> void:
	match _mode:
		SelectMangerMode.SHOW_MOVE:
			_area.modulate = Color8(127, 175, 0, 127)
		
		SelectMangerMode.SHOW_ATTACK:
			_area.modulate = Color8(127, 0, 175, 127)
		
		SelectMangerMode.MOVE:
			_area.modulate = Color8(127, 175, 175, 127)
		
		SelectMangerMode.ATTACK:
			_area.modulate = Color8(175, 0, 0, 127)
		
		SelectMangerMode.SKILL:
			_area.modulate = Color8(150, 100, 200, 127)




## 获取位置上最顶层的区域
## 从最后面开始遍历
## 返回一个数组
## [下标, 名字]
func get_position_top_area(_position: Vector2) -> Array:
	for i in range(layer.size() - 1, -1, -1):
		for a in layer[i]["areas"]:
			if is_instance_valid(a):
				if a.position == _position:
					return [i, layer[i]["name"]]
	return []




## 合并层级
## _a 的模式、回调等信息都会被 _to 覆盖
## _a 的 areas 会与 _to 的 areas 相加（_a 的会加到末尾）
## _a 会被销毁
## 合并层级会让一些索引失效，所以会返回一个新索引
func merge_layer(_a: Dictionary, _to: Dictionary) -> int:
	for a in _a["areas"]:
		_to["areas"].append(a)
	_a["areas"].clear()
	remove_layer_name(_a["name"])
	for i in range(0, layer.size()):
		if layer[i] == _to:
			return i
	return -1




## 指针移动调用
## 移动到区域上时，如果有回调就会调用
func pointer_move(_pointer: ScenePointer) -> void:
	var ads: Array[Dictionary] = get_is_accept_move_layer()
	var res: Array[Dictionary] = get_position_area_all_layer(_pointer.position, ads)
	# 倒序遍历，从最顶层开始
	for i in range(res.size() - 1, -1, -1):
		var lay: Dictionary = res[i]
		lay["target_position"] = _pointer.position # 增加一个目标位置的参数
		# 调用回调并判断返回值
		# 如果返回 true 就会直接跳过剩下的 move 调用
		if lay["move_callable"].call(lay):
			return




## 获取受理移动的所有layer
## 返回一个数组，越后面的元素越高层
func get_is_accept_move_layer() -> Array[Dictionary]:
	var result: Array[Dictionary] = []
	for lay in layer:
		if lay["is_accept_move"]:
			result.append(lay)
	return result




## 获取位置上的所有layer区域与_position重叠的layer
## 如果 _arr 不为空的话就会检查传入的参数
func get_position_area_all_layer(_position: Vector2, _arr: Array[Dictionary] = []) -> Array[Dictionary]:
	var result: Array[Dictionary] = []
	if _arr.is_empty():
		for i in range(layer.size() - 1, -1, -1):
			for a in layer[i]["areas"]:
				if not is_instance_valid(a):
					continue
				if a.position == _position:
					result.append(layer[i])
	else:
		for dic in _arr:
			for a in dic["areas"]:
				if not is_instance_valid(a):
					continue
				if a.position == _position:
					result.append(dic)
	return result
